﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ARR.Entities;
using ARR.DataModel.Repositories;
using ARR.Entities.Gateways;
using DDF.Entity;
using System.Transactions;
using System.ServiceModel;
using ARR.Shared;
using System.Reflection;
using System.Threading;

namespace ARR.Services.Domain
{
    public static class RangeReviewDomain
    {
        private static List<Country> countriesCache;
        private static List<Category> categoriesCache;
        private static List<Currency> currenciesCache;
        private static List<RangeReviewStore> rrStoresCache;
        private static List<RangeReviewSetup> rrSetupsCache;
        private static List<RangeReviewBenchmark> rrBenchmarksCache;
        private static List<RangeReviewSetupAttribute> rrSetupAttributesCache;
        private static List<AttributeType> attributeTypesCache;
        private static List<Store> storesCache;


        public static List<RangeReview> GetAll(int countryId, bool lazyLoad)
        {
            var rows = RangeReviewsRepository.Select(r => r.CountryId == countryId);
            var rangeReviews = rows.ConvertAll<RangeReview>(row => new RangeReview(row));

            if (!lazyLoad)
            {
                LoadPropertiesCache();
                rangeReviews.ForEach(rr => FillProperties(rr));
            }

            rangeReviews.ForEach(rr => rr.GetRow().ChangeState(EntityState.Original));
            rangeReviews.ForEach(rr => rr.ChangeState(EntityState.Original));

            return rangeReviews;
        }

        public static RangeReview GetById(int rangeReviewId, bool lazyLoad)
        {
            var rrRow = RangeReviewsRepository.Select(rr => rr.Id == rangeReviewId).SingleOrDefault();
            var rangeReview = new RangeReview(rrRow);

            if (!lazyLoad)
            {
                LoadPropertiesCache(rangeReviewId);
                FillProperties(rangeReview);
            }

            rangeReview.GetRow().ChangeState(EntityState.Original);
            rangeReview.ChangeState(EntityState.Original);

            return rangeReview;
        }

        public static RangeReview GetByTitle(string title, int countryId, bool lazyLoad)
        {
            var rrRow = RangeReviewsRepository.Select(rr => rr.Title == title && rr.CountryId == countryId).SingleOrDefault();
            var rangeReview = new RangeReview(rrRow);

            if (!lazyLoad)
            {
                LoadPropertiesCache();
                FillProperties(rangeReview);
            }

            rangeReview.ChangeState(EntityState.Original);

            return rangeReview;
        }

        public static RangeReviewStore GetRangeReviewSameStore(int rangeReviewId)
        {
            var rrSameStore = RangeReviewStoresRepository.Select(x => x.RangeReviewId == rangeReviewId && x.IsSameStore == true).SingleOrDefault();

            if (rrSameStore != null)
            {
                RangeReviewStore rrStore = new RangeReviewStore(rrSameStore);

                var store = StoresRepository.Select(x => x.Id == rrSameStore.StoreId).SingleOrDefault();
                if (store != null)
                {
                    rrStore.Store = new Store(store);

                    return rrStore;
                }
            }

            return null;

        }

        public static List<RangeReviewBenchmark> GetRangeReviewBenchmarks(int rangeReviewId)
        {
            if (rrBenchmarksCache == null)
            {
                LoadPropertiesCache();
            }

            //var benchmarkRows = RangeReviewBenchmarksRepository.Select(bm => bm.RangeReviewSourceId == rangeReviewId);
            var benchmarks = rrBenchmarksCache.Where(x => x.RangeReviewSourceId == rangeReviewId).ToList();//benchmarkRows.ConvertAll<RangeReviewBenchmark>(row => new RangeReviewBenchmark(row));

            foreach (RangeReviewBenchmark bench in rrBenchmarksCache)
            {
                bench.TargetCurrency = CountriesDomain.GetCurrencyById(bench.TargetCurrencyId);

                //if (bench.RangeReviewTargetId.HasValue)
                //{
                //    var target = RangeReviewsRepository.Select(r => r.Id == bench.RangeReviewTargetId.Value).SingleOrDefault();

                //    if (target != null)
                //    {
                //        bench.RangeReviewTargetTitle = target.Title;
                //    }
                //}

                if (bench.StoreGroupId.HasValue)
                {
                    var row = StoreGroupsRepository.Select(g => g.Id == bench.StoreGroupId.Value).SingleOrDefault();
                    bench.StoreGroup = new StoreGroup(row);

                    var memeberRows = StoreGroupMembersRepository.Select(gm => gm.StoreGroupId == bench.StoreGroupId.Value);
                    bench.StoreGroup.Members = memeberRows.ConvertAll<StoreGroupMember>(mr => new StoreGroupMember(mr));

                    foreach (StoreGroupMember member in bench.StoreGroup.Members)
                    {
                        member.Store = StoresDomain.GetById(member.StoreId);
                    }

                    bench.StoreGroup.ChangeState(EntityState.Original);
                }

                if (bench.HistoryGroupId.HasValue)
                {
                    var row = HistoryGroupsRepository.Select(x => x.Id == bench.HistoryGroupId.Value).SingleOrDefault();
                    bench.HistoryGroup = new HistoryGroup(row);

                    var memberRows = HistoryGroupMembersRepository.Select(x => x.HistoryGroupId == bench.HistoryGroupId.Value);
                    bench.HistoryGroup.Members = memberRows.ConvertAll<HistoryGroupMember>(x => new HistoryGroupMember(x));


                    foreach (HistoryGroupMember member in bench.HistoryGroup.Members)
                    {
                        member.History = HistoryDomain.GetById(member.HistoryId);

                        member.History.TargetRate = member.TargetRate;
                        member.History.TargetSpacesConvertion = member.TargetSpacesConversion;
                        member.History.TargetFuelConvertion = member.TargetFuelsConversion;
                    }

                    bench.HistoryGroup.ChangeState(EntityState.Original);
                }


                bench.GetRow().ChangeState(EntityState.Original);
                bench.ChangeState(EntityState.Original);
            }

            return benchmarks;
        }

        //Problemas de performance. Ahora se usa el metodo GetRangeReviewSetupPerf
        public static List<RangeReviewSetup> GetRangeReviewSetups2(int rangeReviewId, int categoryId)
        {
            if (categoriesCache == null)
            {
                LoadPropertiesCache();
            }

            var level2Categories = categoriesCache.Where(x => x.Level == 2).ToList();

            foreach (var cat in level2Categories)
            {
                cat.SubCategories = categoriesCache.Where(x => x.ParentId == cat.Id).ToList();
            }

            List<RangeReviewSetup> rrSetups = new List<RangeReviewSetup>();
            if (categoryId == 0)
            {
                rrSetups = rrSetupsCache.Where(x => x.RangeReviewId == rangeReviewId).ToList();
            }
            else
            {
                Category level2Category = level2Categories.Where(x => x.Id == categoryId).FirstOrDefault();
                if (level2Category != null)
                {
                    rrSetups = rrSetupsCache.Where(x => x.RangeReviewId == rangeReviewId && x.CategoryId == categoryId).ToList();

                    //Traigo las subcategorias
                    foreach (var childCategory in categoriesCache.Where(cat => cat.ParentId == categoryId))
                    {
                        rrSetups.AddRange(rrSetupsCache.Where(x => x.RangeReviewId == rangeReviewId && x.CategoryId == childCategory.Id));
                    }
                }
                else
                {
                    rrSetups = rrSetupsCache.Where(x => x.RangeReviewId == rangeReviewId && x.CategoryId == categoryId).ToList();
                }
            }

            RangeReviewSetup rrSetup;

            //Genero un Setup para cada categoria y Subcategoria
            foreach (Category cat in level2Categories)
            {
                //Si ya existe en la BD lo uso.
                rrSetup = rrSetups.SingleOrDefault(x => x.CategoryId == cat.Id);
                //Sino creo uno nuevo.
                if (rrSetup == null)
                {
                    rrSetup = new RangeReviewSetup { RangeReviewId = rangeReviewId, CategoryId = cat.Id };
                    rrSetups.Add(rrSetup);
                }

                //Seteo la categoria.
                rrSetup.Category = cat;

                //Genero los atributos
                var rrSetupAttributes = rrSetupAttributesCache.Where(a => a.RangeReviewSetupId == rrSetup.Id);

                rrSetup.Attributes = new List<RangeReviewSetupAttribute>();
                foreach (AttributeType type in attributeTypesCache)
                {
                    var attribute = rrSetupAttributes.SingleOrDefault(a => a.AttributeTypeId == type.Id);

                    if (attribute != null)
                    {
                        rrSetup.Attributes.RemoveAll(a => a.AttributeTypeId == type.Id);
                        var rrAtt = attribute;
                        rrAtt.IsChecked = true;

                        rrSetup.Attributes.Add(rrAtt);
                    }
                    else
                    {
                        rrSetup.Attributes.Add(new RangeReviewSetupAttribute { AttributeTypeId = type.Id });
                    }
                }

                //Lo mismo para cada subcategoria
                foreach (Category subcat in cat.SubCategories)
                {
                    //Si ya existe en la BD lo uso.
                    rrSetup = rrSetups.SingleOrDefault(x => x.CategoryId == subcat.Id);

                    //Sino creo uno nuevo.
                    if (rrSetup == null)
                    {
                        rrSetup = new RangeReviewSetup { RangeReviewId = rangeReviewId, CategoryId = subcat.Id };
                    }

                    //Lo agrego como hijo
                    var parent = rrSetups.Single(x => x.CategoryId == cat.Id);
                    if (parent.SubCategoriesSetups == null)
                    {
                        parent.SubCategoriesSetups = new List<RangeReviewSetup>() { rrSetup };
                    }
                    else
                    {
                        parent.SubCategoriesSetups.Add(rrSetup);
                    }


                    //Seteo la categoria.
                    rrSetup.Category = subcat;

                    //Genero los atributos
                    var rrSetupSubCatAttributes = rrSetupAttributesCache.Where(a => a.RangeReviewSetupId == rrSetup.Id);

                    rrSetup.Attributes = new List<RangeReviewSetupAttribute>();
                    foreach (AttributeType type in attributeTypesCache)
                    {
                        var attribute = rrSetupSubCatAttributes.SingleOrDefault(a => a.AttributeTypeId == type.Id);

                        if (attribute != null)
                        {
                            rrSetup.Attributes.RemoveAll(a => a.AttributeTypeId == type.Id);
                            var rrAtt = attribute;
                            rrAtt.IsChecked = true;

                            rrSetup.Attributes.Add(rrAtt);
                        }
                        else
                        {
                            rrSetup.Attributes.Add(new RangeReviewSetupAttribute { AttributeTypeId = type.Id });
                        }
                    }

                }

            }

            rrSetups.RemoveAll(x => x.Category.Level == 3);

            foreach (RangeReviewSetup setup in rrSetups)
            {
                if (setup.SubCategoriesSetups != null)
                {
                    foreach (RangeReviewSetup subcatSetup in setup.SubCategoriesSetups)
                    {
                        subcatSetup.ChangeState(EntityState.Original);
                    }
                }

                setup.ChangeState(EntityState.Original);
            }


            return rrSetups;
        }

        public static List<RangeReviewSetup> GetRangeReviewSetups(int rangeReviewId, int categoryId)
        {
            List<RangeReviewSetup> rrSetups = new List<RangeReviewSetup>();

            if (categoryId != 0)
            {
                if (categoriesCache == null)
                {
                    LoadPropertiesCache(rangeReviewId);
                }

                Category cat = categoriesCache.Where(x => x.Id == categoryId).FirstOrDefault();
                if (cat != null)
                {
                    rrSetups = rrSetupsCache.Where(x => x.RangeReviewId == rangeReviewId && x.CategoryId == categoryId).ToList();

                    //Traigo las subcategorias
                    foreach (var childCategory in categoriesCache.Where(x => x.ParentId == categoryId))
                    {
                        rrSetups.AddRange(rrSetupsCache.Where(x => x.RangeReviewId == rangeReviewId && x.CategoryId == childCategory.Id));
                    }
                }
                else
                {
                    rrSetups = rrSetupsCache.Where(x => x.RangeReviewId == rangeReviewId && x.CategoryId == categoryId).ToList();
                }
            }
            else
            {

                var existing = rrSetupsCache.Where(x => x.RangeReviewId == rangeReviewId);

                RangeReviewSetup rrSetup;
                RangeReviewSetup rrSetupSubCat;
                foreach (var level2Category in categoriesCache.Where(x => x.Level == 2))
                {
                    rrSetup = existing.SingleOrDefault(x => x.CategoryId == level2Category.Id);

                    if (rrSetup == null)
                    {
                        rrSetup = new RangeReviewSetup { RangeReviewId = rangeReviewId, CategoryId = level2Category.Id };
                    }

                    rrSetup.Category = level2Category;

                    foreach (var level3Category in categoriesCache.Where(x => x.ParentId == level2Category.Id))
                    {
                        rrSetupSubCat = existing.SingleOrDefault(x => x.CategoryId == level3Category.Id);

                        if (rrSetupSubCat == null)
                        {
                            rrSetupSubCat = new RangeReviewSetup { RangeReviewId = rangeReviewId, CategoryId = level3Category.Id };
                        }

                        rrSetupSubCat.Category = level3Category;

                        var rrSubCategorySetupAttributes = rrSetupAttributesCache.Where(a => a.RangeReviewSetupId == rrSetupSubCat.Id);
                        rrSetupSubCat.Attributes = new List<RangeReviewSetupAttribute>();
                        foreach (AttributeType type in attributeTypesCache)
                        {
                            var attribute = rrSubCategorySetupAttributes.SingleOrDefault(a => a.AttributeTypeId == type.Id);

                            if (attribute != null)
                            {
                                rrSetupSubCat.Attributes.RemoveAll(a => a.AttributeTypeId == type.Id);
                                var rrAtt = attribute;
                                rrAtt.IsChecked = true;

                                rrSetupSubCat.Attributes.Add(rrAtt);
                            }
                            else
                            {
                                rrSetupSubCat.Attributes.Add(new RangeReviewSetupAttribute { AttributeTypeId = type.Id });
                            }
                        }

                        if (rrSetup.SubCategoriesSetups == null)
                        {
                            rrSetup.SubCategoriesSetups = new List<RangeReviewSetup>();
                        }

                        rrSetup.SubCategoriesSetups.Add(rrSetupSubCat);
                    }

                    var rrSetupAttributes = rrSetupAttributesCache.Where(a => a.RangeReviewSetupId == rrSetup.Id);
                    rrSetup.Attributes = new List<RangeReviewSetupAttribute>();
                    foreach (AttributeType type in attributeTypesCache)
                    {
                        var attribute = rrSetupAttributes.SingleOrDefault(a => a.AttributeTypeId == type.Id);

                        if (attribute != null)
                        {
                            rrSetup.Attributes.RemoveAll(a => a.AttributeTypeId == type.Id);
                            var rrAtt = attribute;
                            rrAtt.IsChecked = true;

                            rrSetup.Attributes.Add(rrAtt);
                        }
                        else
                        {
                            rrSetup.Attributes.Add(new RangeReviewSetupAttribute { AttributeTypeId = type.Id });
                        }
                    }

                    rrSetups.Add(rrSetup);
                }
            }


            //TODO: Agregar missing para las subcategorias.
            //SetupMissings            
            var missings = RangeReviewSetupRepository.RangeReviewSetup_CheckMissings(rangeReviewId, 0, false);

            foreach (var setup in rrSetups)
            {
                setup.Missings = new Dictionary<string, int>();
                if (setup.Category.Level == 2) //Si es una categoria agrupo los resultados para mostrar los totales
                {
                    var grouped = from m in missings
                                  where m.ParentId == setup.CategoryId
                                  group m by new { m.ParentId, m.Attribute } into g
                                  select new { Attribute = g.Key.Attribute, ParentId = g.Key.ParentId, Missings = g.Sum(x => x.Missings) };

                    foreach (var missing in grouped)
                    {
                        setup.Missings.Add(missing.Attribute, missing.Missings);
                    }
                }
                else if (setup.Category.Level == 3)
                {
                    foreach (var missing in missings.Where(x => x.CategoryId == setup.CategoryId))
                    {
                        setup.Missings.Add(missing.Attribute, missing.Missings);
                    }
                }

                setup.ChangeState(EntityState.Original);
            }


            foreach (RangeReviewSetup setup in rrSetups)
            {
                if (setup.SubCategoriesSetups != null)
                {
                    foreach (RangeReviewSetup subcatSetup in setup.SubCategoriesSetups)
                    {
                        subcatSetup.ChangeState(EntityState.Original);
                    }
                }

                setup.ChangeState(EntityState.Original);
            }


            return rrSetups;
        }

        public static List<RangeReviewStore> GetRangeReviewStores(RangeReview range)
        {
            if (rrStoresCache == null)
            {
                LoadPropertiesCache();
            }

            List<RangeReviewStore> rrStores = rrStoresCache.Where(x => x.RangeReviewId == range.Id).ToList();
            List<Store> stores = storesCache.Where(x => x.CountryId == range.CountryId).ToList();

            //foreach (var store in stores)
            //{
            //    var rrStore = rrStores.SingleOrDefault(x => x.StoreId == store.Id);

            //    if (rrStore == null)
            //    {
            //        rrStores.Add(new RangeReviewStore { RangeReviewId = range.Id, StoreId = store.Id, Store = store });
            //    }
            //    else
            //    {
            //        rrStore.IsSelected = true;
            //    }
            //}

            rrStores.ForEach(x => x.Store = storesCache.Single(st => st.Id == x.StoreId));
            rrStores.ForEach(x => x.ChangeState(EntityState.Original));

            return rrStores.OrderBy(x => x.Store.Code).ToList();
        }

        public static void SaveAll(List<RangeReview> rangeReviews)
        {
            try
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    var toBeSaved = rangeReviews.Where(rr => rr.GetEntityState() != EntityState.Original);

                    foreach (RangeReview range in toBeSaved)
                    {
                        Save(range);
                    }

                    scope.Complete();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static RangeReview SaveNewAndGetIt(RangeReview rangeReview)
        {
            if(rangeReview.GetEntityState() == EntityState.New)
            {
                RangeReviewsRepository.Insert(rangeReview.GetRow());
                return GetById(rangeReview.Id, true);
            }

            return null;
        }


        private static void FillProperties(RangeReview range)
        {
            range.Country = countriesCache.Single(x => x.Id == range.CountryId); //CountriesDomain.GetById(range.CountryId);
            range.TargetCurrency = currenciesCache.Single(x => x.Id == range.TargetCurrencyId); //CountriesDomain.GetCurrencyById(range.TargetCurrencyId);

            range.RangeReviewStores = GetRangeReviewStores(range);

            range.RangeReviewSetups = GetRangeReviewSetups(range.Id, 0);

            //TODO: Agregar missing para las subcategorias.
            //SetupMissings            
            //var missings = RangeReviewSetupRepository.RangeReviewSetup_CheckMissings(range.Id, 0, false);

            //foreach (var setup in range.RangeReviewSetups)
            //{
            //    setup.Missings = new Dictionary<string, int>();
            //    if (setup.Category.Level == 2) //Si es una categoria agrupo los resultados para mostrar los totales
            //    {
            //        var grouped = from m in missings
            //                      where m.ParentId == setup.CategoryId
            //                      group m by new { m.ParentId, m.Attribute } into g
            //                      select new { Attribute = g.Key.Attribute, ParentId = g.Key.ParentId, Missings = g.Sum(x => x.Missings) };

            //        foreach (var missing in grouped)
            //        {
            //            setup.Missings.Add(missing.Attribute, missing.Missings);
            //        }
            //    }
            //    else if (setup.Category.Level == 3)
            //    {
            //        foreach (var missing in missings.Where(x => x.CategoryId == setup.CategoryId))
            //        {
            //            setup.Missings.Add(missing.Attribute, missing.Missings);
            //        }
            //    }

            //    setup.ChangeState(EntityState.Original);
            //}
                        
            range.Benchmarks = GetRangeReviewBenchmarks(range.Id);
            
        }

        private static void Save(RangeReview range)
        {
            if (range.IsValid)
            {
                //Guardo el Range Review
                if (range.GetRow().GetEntityState() == EntityState.New)
                {
                    RangeReviewsRepository.Insert(range.GetRow());
                }
                else if (range.GetRow().GetEntityState() == EntityState.Modified)
                {
                    RangeReviewsRepository.Update(range.GetRow());
                }


                //Guardo las tiendas
                foreach (var rrStore in range.RangeReviewStores)
                {
                    //Primero guardo las tiendas nuevas/modificadas
                    if (rrStore.Store.GetEntityState() == EntityState.New)
                    {
                        StoresRepository.Insert(rrStore.Store.GetRow());
                    }
                    else if (rrStore.Store.GetEntityState() == EntityState.Modified)
                    {
                        StoresRepository.Update(rrStore.Store.GetRow());
                    }

                    if (rrStore.GetRow().GetEntityState() == EntityState.New)
                    {
                        rrStore.RangeReviewId = range.Id;
                        rrStore.StoreId = rrStore.Store.Id;
                        RangeReviewStoresRepository.Insert(rrStore.GetRow());
                    }
                    else if (rrStore.GetRow().GetEntityState() == EntityState.Modified)
                    {
                        RangeReviewStoresRepository.Update(rrStore.GetRow());
                    }

                    //LG: Toda esta lógica no va porque quedo obsoleta 
                    ////Despues actualizo los datos de la muestra del RangeReview
                    //if (rrStore.IsSelected)
                    //{
                    //    if (rrStore.GetRow().GetEntityState() == EntityState.New)
                    //    {
                    //        rrStore.RangeReviewId = range.Id;
                    //        rrStore.StoreId = rrStore.Store.Id;
                    //        RangeReviewStoresRepository.Insert(rrStore.GetRow());
                    //    }
                    //    else if (rrStore.GetRow().GetEntityState() == EntityState.Modified)
                    //    {
                    //        RangeReviewStoresRepository.Update(rrStore.GetRow());
                    //    }
                    //}
                    //else
                    //{
                    //    //Si no esta seleccionado y State!=New lo tengo que borrar de la BD.
                    //    if (rrStore.GetRow().GetEntityState() != EntityState.New)
                    //    {
                    //        RangeReviewStoresRepository.Delete(x => x.Id == rrStore.Id);
                    //    }
                    //}
                }

                #region Old Guardar tiendas
                //RangeReviewStoresRepository.Delete(st => st.RangeReviewId == range.Id);
                //foreach (var rrStore in range.RangeReviewStores)
                //{
                //    rrStore.Id = 0;
                //    rrStore.RangeReviewId = range.Id;
                //    RangeReviewStoresRepository.Insert(rrStore.GetRow());
                //} 
                #endregion



                //Guardo los Benchmarks
                foreach (var benchmark in range.Benchmarks)
                {
                    if (benchmark.GetEntityState() != EntityState.Original)
                    {
                        if (benchmark.StoreGroup != null)
                        {
                            var group = benchmark.StoreGroup;

                            if (group.GetEntityState() == EntityState.New)
                            {
                                StoreGroupsRepository.Insert(group.GetRow());
                            }
                            else if (group.GetEntityState() == EntityState.Modified)
                            {
                                StoreGroupsRepository.Update(group.GetRow());
                                StoreGroupMembersRepository.Delete(m => m.StoreGroupId == group.Id);
                            }

                            foreach (var member in group.Members)
                            {
                                member.StoreGroupId = group.Id;

                                StoreGroupMembersRepository.Insert(member.GetRow());
                            }

                            benchmark.StoreGroupId = benchmark.StoreGroup.Id;
                        }

                        if (benchmark.HistoryGroup != null)
                        {
                            var group = benchmark.HistoryGroup;

                            if (group.GetEntityState() == EntityState.New)
                            {
                                HistoryGroupsRepository.Insert(group.GetRow());
                            }
                            else if (group.GetEntityState() == EntityState.Modified)
                            {
                                HistoryGroupsRepository.Update(group.GetRow());
                                HistoryGroupMembersRepository.Delete(x => x.HistoryGroupId == group.Id);
                            }

                            foreach (var member in group.Members)
                            {
                                member.HistoryGroupId = group.Id;

                                HistoryGroupMembersRepository.Insert(member.GetRow());
                            }

                            benchmark.HistoryGroupId = benchmark.HistoryGroup.Id;
                        }


                        benchmark.RangeReviewSourceId = range.Id;

                        if (benchmark.GetEntityState() == EntityState.New)
                        {
                            RangeReviewBenchmarksRepository.Insert(benchmark.GetRow());
                        }
                        else if (benchmark.GetEntityState() == EntityState.Modified)
                        {
                            RangeReviewBenchmarksRepository.Update(benchmark.GetRow());
                        }
                    }

                }

                //Guardo los Setups

                if (range.RangeReviewSetups != null)
                {
                    var setupsChanged = range.RangeReviewSetups.Where(stp => stp.GetEntityState() == EntityState.Modified);

                    foreach (RangeReviewSetup setup in setupsChanged)
                    {
                        SaveRangeSetups(setup, range);

                        foreach (RangeReviewSetup subCategorySetup in setup.SubCategoriesSetups)
                        {
                            SaveRangeSetups(subCategorySetup, range);
                        }
                    }
                }

            }
            else
            {
                throw new FaultException(string.Format(Errors.CanNotSaveRangeReviewBecauseOf, range.Title, range.Error));
            }
        }

        private static void SaveRangeSetups(RangeReviewSetup setup, RangeReview range)
        {
            setup.RangeReviewId = range.Id;

            if (setup.Id == 0)
            {
                RangeReviewSetupRepository.Insert(setup.GetRow());
            }
            else
            {
                RangeReviewSetupRepository.Update(setup.GetRow());
            }

            RangeReviewSetupAttributesRepository.Delete(att => att.RangeReviewSetupId == setup.Id);

            if (setup.Attributes != null && setup.Attributes.Any())
            {
                var attributes = setup.Attributes.Where(att => att.IsChecked);

                foreach (var attribute in attributes)
                {
                    attribute.Id = 0;
                    attribute.RangeReviewSetupId = setup.Id;
                    RangeReviewSetupAttributesRepository.Insert(attribute.GetRow());
                }
            }

        }

        private static void LoadPropertiesCache()
        {
            //Cacheo datos en memoria.
            countriesCache = CountriesDomain.GetAll();

            categoriesCache = CategoriesDomain.GetAll();

            currenciesCache = CountriesDomain.GetAllCurrencies();

            rrStoresCache = RangeReviewStoresRepository.Select().ConvertAll<RangeReviewStore>(row => new RangeReviewStore(row));
            rrStoresCache.ForEach(x =>
                {
                    x.GetRow().ChangeState(EntityState.Original);
                    x.ChangeState(EntityState.Original);
                });

            storesCache = StoresDomain.GetAll(true);

            rrBenchmarksCache = RangeReviewBenchmarksRepository.Select().ConvertAll<RangeReviewBenchmark>(row => new RangeReviewBenchmark(row));
            rrBenchmarksCache.ForEach(x => x.ChangeState(EntityState.Original));

            rrSetupsCache = RangeReviewSetupRepository.Select().ConvertAll<RangeReviewSetup>(row => new RangeReviewSetup(row));
            rrSetupsCache.ForEach(x => x.ChangeState(EntityState.Original));

            rrSetupAttributesCache = RangeReviewSetupAttributesRepository.Select().ConvertAll<RangeReviewSetupAttribute>(row => new RangeReviewSetupAttribute(row));
            rrSetupAttributesCache.ForEach(x => x.ChangeState(EntityState.Original));

            attributeTypesCache = AttributesDomain.GetAllTypes();

        }

        private static void LoadPropertiesCache(int rangeReviewId)
        {
            //Cacheo datos en memoria.
            countriesCache = CountriesDomain.GetAll();

            categoriesCache = CategoriesDomain.GetAll();

            currenciesCache = CountriesDomain.GetAllCurrencies();

            rrStoresCache = RangeReviewStoresRepository.Select(x => x.RangeReviewId == rangeReviewId).ConvertAll<RangeReviewStore>(row => new RangeReviewStore(row));
            rrStoresCache.ForEach(x =>
            {
                x.GetRow().ChangeState(EntityState.Original);
                x.ChangeState(EntityState.Original);
            });

            var range = RangeReviewsRepository.Select(x => x.Id == rangeReviewId).Single();
            storesCache = StoresDomain.GetByCountry(range.CountryId, true);

            rrBenchmarksCache = RangeReviewBenchmarksRepository.Select(x => x.RangeReviewSourceId == rangeReviewId).ConvertAll<RangeReviewBenchmark>(row => new RangeReviewBenchmark(row));
            rrBenchmarksCache.ForEach(x => x.ChangeState(EntityState.Original));

            rrSetupsCache = RangeReviewSetupRepository.Select(x => x.RangeReviewId == rangeReviewId).ConvertAll<RangeReviewSetup>(row => new RangeReviewSetup(row));
            rrSetupsCache.ForEach(x => x.ChangeState(EntityState.Original));

            rrSetupAttributesCache = RangeReviewSetupAttributesRepository.Select().ConvertAll<RangeReviewSetupAttribute>(row => new RangeReviewSetupAttribute(row));
            rrSetupAttributesCache.ForEach(x => x.ChangeState(EntityState.Original));

            attributeTypesCache = AttributesDomain.GetAllTypes();
        }

    }
}
